package com.arpa.ntocc.common.security.aspect;

import com.arpa.ntocc.common.common.constant.StrConsts;
import com.arpa.ntocc.common.common.exception.AuthorizeTokenException;
import com.arpa.ntocc.common.common.exception.PermissionException;
import com.arpa.ntocc.common.common.exception.RoleException;
import com.arpa.ntocc.common.domain.dto.UserInfoDTO;
import com.arpa.ntocc.common.domain.vo.RoleVO;
import com.arpa.ntocc.common.security.annotation.Logical;
import com.arpa.ntocc.common.security.annotation.NeedRole;
import com.arpa.ntocc.common.service.IPartyRoleService;
import com.arpa.ntocc.common.service.authorize.AuthorizeTokenService;
import lombok.extern.log4j.Log4j2;
import org.apache.oltu.oauth2.rs.request.OAuthAccessResourceRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 角色校验切片处理类
 * @Author liuyj
 * @Date 2019-11-07 17:18:17
 */
@Component
@Aspect
@Log4j2
public class NeedRoleAop {

    @Autowired
    private AuthorizeTokenService authorizeTokenService;
    @Autowired
    private IPartyRoleService partyRoleService;

    /**
     * 定义有一个切入点，范围为ntocc包下的类
     */
    @Pointcut("execution(public * com.arpa..*.*(..))")
    public void annotationPointCut() {
    }

    /**
     * 切面before判断用户是否登录，是否具有权限
     * @param joinPoint
     * @throws Exception
     */
    @Before("annotationPointCut()")
    public void before(JoinPoint joinPoint) throws Exception {
        try {
            MethodSignature sign =  (MethodSignature)joinPoint.getSignature();
            Method method = sign.getMethod();
            NeedRole annotation = method.getAnnotation(NeedRole.class);
            if(annotation!=null){
                //判断是否登录了
                if(!isLogin()){
                    throw new AuthorizeTokenException("请先登录");
                }
                //判断用户是否有该角色
                String[] requiredRoles=annotation.value();
                Logical logical = annotation.logical();
                if(!hasRole(requiredRoles,logical)){
                    throw new RoleException(Arrays.toString(requiredRoles));
                }
            }
        }catch(AuthorizeTokenException authorizeTokenException){
            throw authorizeTokenException;
        }catch(RoleException roleException){
            throw roleException;
        }catch(PermissionException permissionExeption){
            throw permissionExeption;
        }catch (Exception e){
            log.error(StrConsts.CATCH_MESSAGE,e);
            throw e;
        }
    }

    /**
     * 判断是否有角色
     * @param requiredRoles
     * @param logical
     * @return
     */
    private boolean hasRole(String[] requiredRoles, Logical logical) {
        boolean hasRole=false;
        try {
            if(requiredRoles == null || requiredRoles.length == 0){
                hasRole=true;
            }else{
                //查询用户所有角色
                List<String> roleList=getRoleList();

                if(!CollectionUtils.isEmpty(roleList)){
                    //权限 或
                    if(logical==Logical.OR){
                        for(String permissionStr:requiredRoles){
                            if(roleList.contains(permissionStr)){
                                hasRole=true;
                                break;
                            }
                        }
                    }else{//权限 与
                        int needNum=0;
                        for(String roleStr:requiredRoles){
                            if(roleList.contains(roleStr)){
                                needNum++;
                            }
                        }
                        if(needNum == requiredRoles.length){
                            hasRole=true;
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
        }
        return hasRole;
    }

    /**
     * 获取当前登录用户角色list
     * @return
     */
    private List<String> getRoleList() {
        List<String> roleStrList=new ArrayList<>();
        UserInfoDTO userInfoDTO=authorizeTokenService.getUserInfo();
        List<RoleVO> roleList=userInfoDTO.getRoleList();
        if(!CollectionUtils.isEmpty(roleList)){
            roleList.forEach(role -> {
                roleStrList.add(role.getRoles());
            });
        }
        return roleStrList;
    }

    /**
     * 判断是否登录
     * @return
     */
    private boolean isLogin() {
        boolean isLogin=false;
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            //构建OAuth资源请求
            OAuthAccessResourceRequest oauthRequest = new OAuthAccessResourceRequest(request);
            //获取Access Token
            String accessToken = oauthRequest.getAccessToken();
            //验证token合法性
            if (authorizeTokenService.checkTokenAvailable(accessToken)) {
                isLogin=true;
            }
        } catch (Exception e) {
            log.error(StrConsts.CATCH_MESSAGE,e);
        }
        return isLogin;
    }

}
